/**
 * QUANSHI.com Inc.
 * Copyright (c) 2016-2017 All Rights Reserved.
 */
package com.quanshi.scheduler.core.rpc.netcom.jetty;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;

import com.quanshi.scheduler.core.base.Ret;
import com.quanshi.scheduler.core.rpc.codec.RpcRequest;
import com.quanshi.scheduler.core.rpc.codec.RpcResponse;
import com.quanshi.scheduler.core.rpc.netcom.jetty.server.JettyServer;

/**
 * 
 * 
 * @author chinaxiang
 * @version 2017年7月7日 下午10:15:33
 */
public class NetComServerFactory {

    private static final Logger logger = LoggerFactory.getLogger(NetComServerFactory.class);
    
    // ---------------------- server start ----------------------
    private JettyServer                 server = new JettyServer();

    public void start(int port, String ip, String appName) throws Exception {
        logger.info( "start server. appName:{}, ip:{}, port:{}.", appName, ip, port );
        server.start(port, ip, appName);
    }

    // ---------------------- server destroy --------------------
    public void destroy() {
        logger.info( "destroy server." );
        server.destroy();
    }

    // ---------------------- server init ----------------------
    /**
     * init local rpc service map
     */
    private static Map<String, Object> serviceMap = new HashMap<String, Object>();

    public static void putService(Class<?> iface, Object serviceBean) {
        serviceMap.put(iface.getName(), serviceBean);
    }

    public static RpcResponse invokeService(RpcRequest request, Object serviceBean) {
        if (serviceBean == null) {
            serviceBean = serviceMap.get(request.getClassName());
        }

        RpcResponse response = new RpcResponse();

        if (System.currentTimeMillis() - request.getCreateMillisTime() > 180000) {
            response.setResult(new Ret<String>(Ret.FAIL_CODE, "the timestamp difference between admin and executor exceeds the limit."));
            return response;
        }

        try {
            Class<?> serviceClass = serviceBean.getClass();
            String methodName = request.getMethodName();
            Class<?>[] parameterTypes = request.getParameterTypes();
            Object[] parameters = request.getParameters();

            FastClass serviceFastClass = FastClass.create(serviceClass);
            FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);

            Object result = serviceFastMethod.invoke(serviceBean, parameters);

            response.setResult(result);
        } catch (Throwable t) {
            logger.error( "invokeService error.", t );
            response.setError(t.getMessage());
        }

        return response;
    }
}
